// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现测试支持。

package syntax

import (
	"io"
	"regexp"
	"strings"
)

// CommentsDo解析给定的源代码，并为每个
// 注释或错误调用提供的处理程序。如果提供给处理程序的文本以“/”开头，则为
// 注释文本；否则就是错误消息。
func CommentsDo(src io.Reader, handler func(line, col uint, text string)) {
	var s scanner
	s.init(src, handler, comments)
	for s.tok != _EOF {
		s.next()
	}
}

// 错误注释必须以文本“ERROR”msg`或“ERROR msg”开头。
// 忽略“msg”或msg周围的空格。
var errRx = regexp.MustCompile(`^ *ERROR *"?([^"]*)"?`)

// ErrorMap从给定的src中收集所有带有注释文本形式
// `ERROR“msg”或`ERROR msg`的注释，并将它们返回
// as[]错误列表，在一个按行号索引的映射中。位置
// 对于每个错误，都是紧跟在
// 注释前面的标记的位置，错误消息是从
// 注释中提取的消息，同一行上的所有错误按源顺序收集在一个片段中。如果前面没有标记（文件开头出现
// /`ERROR`注释），则
// 记录的位置未知（第行，col=0，0）。如果没有
// 错误注释，则结果为零。
func ErrorMap(src io.Reader) (errmap map[uint][]Error) {
	// 上一个标记的位置
	var base *PosBase
	var prev struct{ line, col uint }

	var s scanner
	s.init(src, func(_, _ uint, text string) {
		if text[0] != '/' {
			return // 错误，忽略
		}
		if text[1] == '*' {
			text = text[:len(text)-2] // 带尾随*/
		}
		if s := errRx.FindStringSubmatch(text[2:]); len(s) == 2 {
			pos := MakePos(base, prev.line, prev.col)
			err := Error{pos, strings.TrimSpace(s[1])}
			if errmap == nil {
				errmap = make(map[uint][]Error)
			}
			errmap[prev.line] = append(errmap[prev.line], err)
		}
	}, comments)

	for s.tok != _EOF {
		s.next()
		if s.tok == _Semi && s.lit != "semicolon" {
			continue // 忽略自动插入的分号
		}
		prev.line, prev.col = s.line, s.col
	}

	return
}
